package com.github.avatar.http;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;

import java.io.InterruptedIOException;


/**
 * @author Jerry Liu
 * @since 2017/3/8
 */
public class HttpClientManager {

    private static final PoolingHttpClientConnectionManager connectionManger;
    private static final int CONNECTION_TIMEOUT = 3000;
    private static final int CONNECTION_REQUEST_TIMEOUT = 3000;
    private static final int MAX_PER_ROUTE = 20;
    private static final int MAX_CONNECTION = 200;
    //private static final int SOCKET_TIMEOUT = 3000;

    static {
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("https", SSLConnectionSocketFactory.getSocketFactory())
            .register("http", PlainConnectionSocketFactory.getSocketFactory())
            .build();

        connectionManger = new PoolingHttpClientConnectionManager(registry);
        connectionManger.setMaxTotal(MAX_CONNECTION);
        connectionManger.setDefaultMaxPerRoute(MAX_PER_ROUTE);
    }

    /**
     * Get HttpClient instance
     * @return HttpClient
     */
    public static HttpClient getHttpClient() {
        RequestConfig config = RequestConfig.custom()
            .setConnectTimeout(CONNECTION_TIMEOUT)
            //.setSocketTimeout(SOCKET_TIMEOUT)
            .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT)
            .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
            .build();

        return HttpClients.custom()
            .setConnectionManager(connectionManger)
            .setDefaultRequestConfig(config)
            //重试机制
            .setRetryHandler((ex, exCount, context) -> {
                //超过三次就放弃
                if (exCount > 3) {
                    return false;
                }

                if (ex instanceof InterruptedIOException) {
                    return false;
                }

                HttpClientContext ctx = HttpClientContext.adapt(context);
                HttpRequest request = ctx.getRequest();

                if (request instanceof HttpEntityEnclosingRequest) {
                    return false;
                }
                return true;
            })
            //存活策略
            .setKeepAliveStrategy((response, context) -> {
                HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
                while (it.hasNext()) {
                    HeaderElement e = it.nextElement();
                    String param = e.getName();
                    String value = e.getValue();
                    if (StringUtils.isNotBlank(value)
                            && param.equalsIgnoreCase("timeout")) {
                        return Long.parseLong(value) * 1000;
                    }
                }

                return 1000;
            })
            .build();
    }

}
